/** timer.c: Timer interrupt related functions
 *
 * Author: 	Nora Tarano <ntarano@andrew.cmu.edu>
 *          Yuan Meng <yuanm@andrew.cmu.edu>
 *          Yipeng Yun <yipengy@andrew.cmu.edu>
 * Date: 	Dec 11, 2011
 */
#include <types.h>
#include <exports.h>
#include <device.h>

#include <arm/timer.h>
#include <arm/interrupt.h>
#include <arm/reg.h>

#include "arm/handler.h"

#define FREQUENCY	3250

volatile unsigned long system_time;

void init_timer(void)
{
	// reset system time
	system_time = 0;
	
	reg_write(OSTMR_OIER_ADDR, OSTMR_OIER_E0);	// enable osmr0 only
	reg_write(OSTMR_OSMR_ADDR(0), 1*FREQUENCY);	// set osmr0
	
	install_int_handler(INT_OSTMR_0, timer_handler);
	
	reg_write(OSTMR_OSSR_ADDR, 0x0);	// clear interrupts
	reg_write(OSTMR_OSCR_ADDR, 0x0);	// start kernel timer
}

void destroy_timer(void)
{
	// disable all timers
	reg_clear(OSTMR_OIER_ADDR, 
		OSTMR_OIER_E0 | OSTMR_OIER_E1 | OSTMR_OIER_E2 | OSTMR_OIER_E3);
	
	// replace timer interrupt with panic handler
	install_int_handler(INT_OSTMR_0, interrupt_panic);
}

void timer_handler(unsigned int int_num __attribute__((unused)))
{
	// check if there is in fact a match
	if (reg_read(OSTMR_OSSR_ADDR) & OSTMR_OSSR_M0)
	{
		// unsigned long oscr = reg_read(OSTMR_OSCR_ADDR);
		system_time += 1;
	
		// acknowledge IRQ
		reg_write(OSTMR_OSSR_ADDR, OSTMR_OSSR_M0);
	
		// reset all registers
		reg_write(OSTMR_OSMR_ADDR(0), 1*FREQUENCY);
		reg_write(OSTMR_OSCR_ADDR, 0x0);
	
		dev_update(system_time);
	}
}

unsigned long get_ticks(void)
{
	return system_time;
}

unsigned long get_millis(void)
{
	return system_time;
}
